package com.qianyitian.hope2.analyzer.util;

import com.qianyitian.hope2.analyzer.model.KLineInfo;
import com.qianyitian.hope2.sdk.funds.FundBar;

import java.util.List;
import java.util.stream.Collectors;

public class AlgorithmUtil {

    public static FundBar[] maxDrawback(List<FundBar> bars, int days) {
        //初始最大值
        double max = Integer.MIN_VALUE;
        //初始最小值
        double min = Integer.MAX_VALUE;
        //初始最大回撤，例如 25%
        double payback = Integer.MIN_VALUE;

        //当前最大值的位置
        int maxIndex = -1;
        //当前最小值的位置
        int minIndex = -1;

        //历史最大值的位置，如果不需要显示具体日期，可以忽略该变量
        int maxDrawbackIndex = -1;
        //历史最小值的位置，如果不需要显示具体日期，可以忽略该变量
        int minDrawbackIndex = -1;

        int start = 0;
        //只计算最近多少天以内的，比如最近200天，如果过大，就计算所有的数据
        if (bars.size() > days) {
            start = bars.size() - days;
        }

        //开始单项扫描
        for (int i = start; i < bars.size(); i++) {
            //获取当前值
            double value = bars.get(i).getValue();
            if (max < value) {
                //保存当前的最大值
                max = value;
                min = value;
                maxIndex = i;
                minIndex = i;
            }
            if (min > value) {
                //保存当前的最小值
                min = value;
                minIndex = i;
            }
            if ((max - min) / max > payback && max != min) {
                //如果，本次的回撤超过了历史最大回撤，更新保存历史最大回撤，和具体日期即最大值和最小值的index位置
                maxDrawbackIndex = maxIndex;
                minDrawbackIndex = minIndex;
                payback = (max - min) / max;
            }
        }
        //返回找到的符合条件的最大值位置和最小值位置
        return new FundBar[]{bars.get(maxDrawbackIndex), bars.get(minDrawbackIndex)};
    }


    public static int[] maxAndMinValue(List<KLineInfo> bars, int startIndex) {
        //初始最大值
        double max = Integer.MIN_VALUE;
        //初始最小值
        double min = Integer.MAX_VALUE;
        //当前最大值的位置
        int maxIndex = -1;
        //当前最小值的位置
        int minIndex = -1;

        int start = startIndex;

        //开始单项扫描
        for (int i = start; i < bars.size(); i++) {
            //获取当前值
            double value = bars.get(i).getClose();
            if (max < value) {
                //保存当前的最大值
                max = value;
                maxIndex = i;
            }
            if (min > value) {
                //保存当前的最小值
                min = value;
                minIndex = i;
            }
        }
        //返回找到的符合条件的最大值位置和最小值位置
        return new int[]{maxIndex, minIndex};
    }


    public static double averageCostByLimitMoney(List<KLineInfo> bars) {
        double ONE_BUY_CASH = 1;
        int barCount = bars.size();
        int limit = Math.min(300, barCount);
        double totalCost = 0;
        double amount = 0;
        for (int i = barCount - limit; i < barCount; i++) {
            totalCost = totalCost + ONE_BUY_CASH;
            amount = amount + (ONE_BUY_CASH / bars.get(i).getClose());
        }
        return Utils.get2Double(totalCost / amount);
    }

    public static double averageCostByLimitAmount(List<KLineInfo> bars) {
        double ONE_BUY_Amount = 1;
        int barCount = bars.size();
        int limit = Math.min(300, barCount);
        double totalCost = 0;
        double amount = 0;
        for (int i = barCount - limit; i < barCount; i++) {
            totalCost = totalCost + ONE_BUY_Amount * bars.get(i).getClose();
            amount = amount + ONE_BUY_Amount;
        }
        return Utils.get2Double(totalCost / amount);
    }

    //n 日线 价格
    public static double maN(List<KLineInfo> bars, int n) {
        int limit = Math.min(bars.size(), n);
        double sum = 0;
        for (int i = bars.size() - limit; i < bars.size(); i++) {
            sum += bars.get(i).getClose();
        }
        return sum / n;
    }


    //n 日线 价格
    public static double[] maN(List<KLineInfo> bars, int n, int daysToNow) {
        List<Double> list = bars.stream().map(item -> item.getClose()).collect(Collectors.toList());
        return maNumber(list, n, daysToNow);
    }

    public static double[] maNumber(List<Double> bars, int n, int daysToNow) {
        if (bars.size() < n + daysToNow) {
            return null;
        }
        double[] result = new double[daysToNow];
        int index = 0;
        for (int i = bars.size() - daysToNow; i < bars.size(); i++) {
            double sum = 0;
            for (int j = i - n + 1; j <= i; j++) {
                sum += bars.get(j);
            }

            result[index] = sum / n;
            index++;
        }
        return result;
    }

}
